package org.jeecg.modules.cascv.image.util;

import cn.hutool.core.io.FileUtil;
import com.NativeImageIO;

import java.util.ArrayList;
import java.util.List;

public class BayerUtil {

    public static int writeBGR(byte[] file, int curLength, byte B, byte G, byte R){
        file[curLength] = B;
        file[curLength+1] = G;
        file[curLength+2] = R;
        return curLength + 3;
    }

    public static int[] getPointPos(int y, int x, int width, int size, int scale){
        int curx = y * width + x;
        int upx = (y - 1) * width + x;
        int downx = (y + 1) * width + x;
//        int fdpos = size - (y+1)*width*3 + x*3;
        int fdpos = ((y/scale)*(width/scale) + x/scale)*3;
//        fdpos = arr[0];
//        curx = arr[1];
//        upx = arr[2];
//        downx = arr[3];
        return new int[]{fdpos, curx, upx, downx};
    }


    public static byte[] writeBayerBmpFile(byte[] data, int width, int height) {
        return writeBayerBmpFile(data, width, height, 1);
    }

    //GB
    public static byte[] writeBayerBmpFile(byte[] data, int width, int height, int scale) {

        int len = data.length;
        int size = (width/ scale) * (height / scale) * 3 + 1000;
        byte[] file = new byte[size];

        int curLength = 0;
        int fdpos = 0;
        int curx = 0;
        int upx = 0;
        int downx = 0;
        int yy = 0;

        int y = height - 1;
        int xx = 0;
        int[] arr = getPointPos(y, xx, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];
        byte B = (byte) (data[curx + 1]&0xff);
        byte G = (byte) (data[curx]&0xff);
        byte R = (byte) (data[upx]&0xff);
        curLength = writeBGR(file, fdpos, B, G, R);

        for (int x = 1; x < width - 1; x+=2) {
            arr = getPointPos(y, x, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];
            xx = x;

            B = (byte) (data[curx]&0xff);
            G = (byte)(((int)(data[curx -1]&0xff) + (int)(data[curx+1]&0xff) + (int)(data[upx]&0xff))/3);
            R = (byte)(((int)(data[upx - 1]&0xff) + (int)(data[upx+1]&0xff))/2);
            curLength = writeBGR(file, fdpos, B, G, R);

            xx = x + 1;
            arr = getPointPos(y, xx, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];

            if(len - curx <= 1){
                continue;
            }

            B = (byte)(((int)(data[curx - 1]&0xff) + (int)(data[curx+1]&0xff))/2);
            G = (byte) (data[curx]&0xff);
            R = (byte) (data[upx]&0xff);
            curLength = writeBGR(file, fdpos, B, G, R);
        }

        arr = getPointPos(y, width - 1, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];

        xx = width - 1;
        B = (byte)(data[curx]&0xff);
        G = (byte)(((int)(data[curx -1]&0xff) + (int)(data[upx]&0xff))/2);
        R = (byte)(data[upx-1]&0xff);
        curLength = writeBGR(file, fdpos, B, G, R);

        for (y = height - 2; y > 1; y-=2) {
            xx = 0;
            arr = getPointPos(y, xx, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];


            B = (byte)(((int)(data[upx + 1]&0xff) + (int)(data[downx+1]&0xff))/2);
            G = (byte)(((int)(data[upx]&0xff) + (int)(data[curx+1]&0xff) + (int)(data[downx]&0xff))/3);
            R = (byte) (data[curx]&0xff);
            curLength = writeBGR(file, fdpos, B, G, R);

            for (int x = 1; x < width - 1; x+=2) {
                xx = x;
                arr = getPointPos(y, xx, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];

                B = (byte)(((int)(data[upx]&0xff) + (int)(data[downx]&0xff))/2);
                G = (byte) (data[curx]&0xff);
                R = (byte)(((int)(data[curx - 1]&0xff) + (int)(data[curx+1]&0xff))/2);
                curLength = writeBGR(file, fdpos, B, G, R);

                xx = x + 1;
                arr = getPointPos(y, xx, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];

                B = (byte)(((int)(data[upx-1]&0xff) + (int)(data[downx-1]&0xff) + (int)(data[upx-1]&0xff) + (int)(data[downx-1]&0xff))/4);
                G = (byte)(((int)(data[upx]&0xff) + (int)(data[downx]&0xff) + (int)(data[curx-1]&0xff) + (int)(data[curx+1]&0xff))/4);
                R = (byte) (data[curx]&0xff);
                curLength = writeBGR(file, fdpos, B, G, R);

            }

            xx = width - 1;
            arr = getPointPos(y, xx, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];


            B = (byte)(((int)(data[upx]&0xff) + (int)(data[downx]&0xff))/2);
            G = (byte) (data[curx]&0xff);
            R = (byte) (data[curx-1]&0xff);
            curLength = writeBGR(file, fdpos, B, G, R);

            xx = 0;
            yy = y - 1;

            arr = getPointPos(yy, xx, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];


            B = (byte) (data[curx+1]&0xff);
            G = (byte) (data[curx]&0xff);
            R = (byte)(((int)(data[upx]&0xff) + (int)(data[downx]&0xff))/2);
            curLength = writeBGR(file, fdpos, B, G, R);
//
            for (int x = 1; x < width - 1; x+=2) {
                xx = x;
                arr = getPointPos(yy, x, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];


                B = (byte) (data[curx]&0xff);
                G = (byte)(((int)(data[upx]&0xff) + (int)(data[downx]&0xff) + (int)(data[curx-1]&0xff) + (int)(data[curx-1]&0xff))/4);
                R = (byte)(((int)(data[upx-1]&0xff) + (int)(data[downx-1]&0xff) + (int)(data[upx-1]&0xff) + (int)(data[downx-1]&0xff))/4);
                curLength = writeBGR(file, fdpos, B, G, R);

                xx = x + 1;
                arr = getPointPos(yy, xx, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];


                B = (byte)(((int)(data[curx-1]&0xff) + (int)(data[curx+1]&0xff))/2);
                G = (byte) (data[curx]&0xff);
                R = (byte)(((int)(data[upx]&0xff) + (int)(data[downx]&0xff))/2);
                curLength = writeBGR(file, fdpos, B, G, R);
            }

            xx = width - 1;
            arr = getPointPos(yy, xx, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];


            B = (byte) (data[curx]&0xff);
            G = (byte)(((int)(data[upx]&0xff) + (int)(data[curx-1]&0xff) + (int)(data[downx]&0xff))/3);
            R = (byte)(((int)(data[upx-1]&0xff) + (int)(data[downx-1]&0xff))/2);
            curLength = writeBGR(file, fdpos, B, G, R);
        }

        y = 0;
        xx = 0;
        arr = getPointPos(y, xx, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];


        B = (byte) (data[downx+1]&0xff);
        G = (byte)(((int)(data[curx+1]&0xff) + (int)(data[downx]&0xff))/2);
        R = (byte) (data[curx]&0xff);
        curLength = writeBGR(file, fdpos, B, G, R);

        for (int x = 1; x < width - 1; x+=2) {
            xx = x;
            arr = getPointPos(y, xx, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];

            B = (byte) (data[downx]&0xff);
            G = (byte) (data[curx]&0xff);
            R = (byte)(((int)(data[curx-1]&0xff) + (int)(data[curx+1]&0xff))/2);
            curLength = writeBGR(file, fdpos, B, G, R);

            xx = x + 1;
            arr = getPointPos(y, xx, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];


            B = (byte)(((int)(data[downx-1]&0xff) + (int)(data[downx+1]&0xff))/2);
            G = (byte)(((int)(data[curx-1]&0xff) + (int)(data[curx+1]&0xff) + (int)(data[downx]&0xff))/3);
            R = (byte) (data[curx]&0xff);
            curLength = writeBGR(file, fdpos, B, G, R);
        }

        xx = width - 1;
        arr = getPointPos(y, xx, width, size, scale);fdpos = arr[0];curx = arr[1];upx = arr[2];downx = arr[3];


        B = (byte) (data[downx]&0xff);
        G = (byte) (data[curx]&0xff);
        R = (byte) (data[curx-1]&0xff);
        curLength = writeBGR(file, fdpos, B, G, R);

        return file;
    }

    public static int[] bayer2RGB_GR(int[] dataArr, int width, int height) {
        return bayer2RGB(dataArr,width,height,"GR", false);
    }

    public static int[] bayer2RGB_RG(int[] dataArr, int width, int height) {
        return bayer2RGB(dataArr,width,height,"RG", false);
    }

    public static int[] bayer2RGB_BG(int[] dataArr, int width, int height) {
        return bayer2RGB(dataArr,width,height,"BG", false);
    }

    public static int[] bayer2RGB_GB(int[] dataArr, int width, int height) {
        return bayer2RGB(dataArr,width,height,"GB", false);
    }

    public static int[] bayer2RGB_GR_3(int[] dataArr, int width, int height) {
        return bayer2RGB(dataArr,width,height,"GR", true);
    }

    public static int[] bayer2RGB_RG_3(int[] dataArr, int width, int height) {
        return bayer2RGB(dataArr,width,height,"RG", true);
    }

    public static int[] bayer2RGB_BG_3(int[] dataArr, int width, int height) {
        return bayer2RGB(dataArr,width,height,"BG", true);
    }

    public static int[] bayer2RGB_GB_3(int[] dataArr, int width, int height) {
        return bayer2RGB(dataArr,width,height,"GB", true);
    }

    public static int[] bayer2RGB(int[] dataArr, int width, int height, String rule, Boolean splitRGB) {
        if (dataArr.length < width * height) {
            return null;
        }
        // 构建排列规则矩阵
        String[][] gr = new String[height][width];
        for (int r = 0; r < height; r++) {
            String g_r = null;
            String b_g = null;
            for (int c = 0; c < width; c++) {
                if ("GR".equalsIgnoreCase(rule) || "RG".equalsIgnoreCase(rule)) {
                    if ((r + 1) % 2 == 0) {
                        if (b_g == null) {
                            b_g = rule.equalsIgnoreCase("GR") ? "B" : "G";
                        } else if ("B".equalsIgnoreCase(b_g)) {
                            b_g = "G";
                        } else if ("G".equalsIgnoreCase(b_g)) {
                            b_g = "B";
                        }
                        gr[r][c] = b_g;
                    } else {
                        if (g_r == null) {
                            g_r = rule.equalsIgnoreCase("GR") ?  "G" : "R";
                        } else if ("G".equalsIgnoreCase(g_r)) {
                            g_r = "R";
                        } else if ("R".equalsIgnoreCase(g_r)) {
                            g_r = "G";
                        }
                        gr[r][c] = g_r;
                    }
                } else {
                    if ((r + 1) % 2 == 0) {
                        if (g_r == null) {
                            g_r = rule.equalsIgnoreCase("BG") ?  "G" : "R";
                        } else if ("G".equalsIgnoreCase(g_r)) {
                            g_r = "R";
                        } else if ("R".equalsIgnoreCase(g_r)) {
                            g_r = "G";
                        }
                        gr[r][c] = g_r;
                    } else {
                        if (b_g == null) {
                            b_g = rule.equalsIgnoreCase("BG") ? "B" : "G";
                        } else if ("B".equalsIgnoreCase(b_g)) {
                            b_g = "G";
                        } else if ("G".equalsIgnoreCase(b_g)) {
                            b_g = "B";
                        }
                        gr[r][c] = b_g;
                    }
                }
            }
        }

        List<Integer> splitRGBList = new ArrayList<>();
        int[] resultArr = new int[dataArr.length];
        for (int r = 0; r < height; r++) {
            for (int c = 0; c < width; c++) {
                // 求数据数组下标值
                int index = width * r + c;

                // 当前数据是绿/红/蓝
                String currentColor = gr[r][c];

                int G = getRGB(currentColor, "G", dataArr, r, c, width, height, index, gr);
                int R = getRGB(currentColor, "R", dataArr, r, c, width, height, index, gr);
                int B = getRGB(currentColor, "B", dataArr, r, c, width, height, index, gr);

                int restlt = colorToRGB(0, R, G, B);
                resultArr[index] = restlt;

                splitRGBList.add(R);
                splitRGBList.add(G);
                splitRGBList.add(B);
            }
        }
        if (splitRGB) {
            int[] resultArr1 = new int[splitRGBList.size()];
            for (int i = 0; i < splitRGBList.size(); i++) {
                resultArr1[i] = splitRGBList.get(i);
            }
            return resultArr1;
        }
        return resultArr;
    }

    private static int getRGB(String currentColor, String color, int[] dataArr, int r, int c, int width, int height, int index, String[][] gr) {
        if (color.equalsIgnoreCase(currentColor)) {
            return dataArr[index];
        }
        int num = 0;

        Integer left = null;
        Integer upLeft = null;
        Integer up = null;
        Integer upRight = null;
        Integer right = null;
        Integer downRight = null;
        Integer down = null;
        Integer downLeft = null;
        // 求left
        if (c - 1 >= 0) {
            if (color.equalsIgnoreCase(gr[r][c - 1])) {
                left = dataArr[width * (r) + (c - 1)];
            }
        }
        // 求upLeft
        if (r - 1 >= 0 && c - 1 >= 0) {
            if (color.equalsIgnoreCase(gr[r - 1][c - 1])) {
                upLeft = dataArr[width * (r - 1) + (c - 1)];
            }
        }
        // 求up
        if (r - 1 >= 0) {
            if (color.equalsIgnoreCase(gr[r - 1][c])) {
                up = dataArr[width * (r - 1) + (c)];
            }
        }
        // 求upRight
        if (r - 1 >= 0 && c + 1 < width) {
            if (color.equalsIgnoreCase(gr[r - 1][c + 1])) {
                upRight = dataArr[width * (r - 1) + (c + 1)];
            }
        }
        // 求right
        if (c + 1 < width) {
            if (color.equalsIgnoreCase(gr[r][c + 1])) {
                right = dataArr[width * (r) + (c + 1)];
            }
        }
        // 求downRight
        if (r + 1 < height && c + 1 < width) {
            if (color.equalsIgnoreCase(gr[r + 1][c + 1])) {
                downRight = dataArr[width * (r + 1) + (c + 1)];
            }
        }
        // 求down
        if (r + 1 < height) {
            if (color.equalsIgnoreCase(gr[r + 1][c])) {
                down = dataArr[width * (r + 1) + (c)];
            }
        }
        // 求downLeft
        if (r + 1 < height && c - 1 >= 0) {
            if (color.equalsIgnoreCase(gr[r + 1][c - 1])) {
                downLeft = dataArr[width * (r + 1) + (c - 1)];
            }
        }

        int sum = 0;
        if (left != null) {
            num++;
            sum += left;
        }
        if (upLeft != null) {
            num++;
            sum += upLeft;
        }
        if (up != null) {
            num++;
            sum += up;
        }
        if (upRight != null) {
            num++;
            sum += upRight;
        }
        if (right != null) {
            num++;
            sum += right;
        }
        if (downRight != null) {
            num++;
            sum += downRight;
        }
        if (down != null) {
            num++;
            sum += down;
        }
        if (downLeft != null) {
            num++;
            sum += downLeft;
        }
        return sum / num;
    }

    public static int colorToRGB(int alpha, int red, int green, int blue) {

        int newPixel = 0;
        newPixel += alpha;
        newPixel = newPixel << 8;
        newPixel += red;
        newPixel = newPixel << 8;
        newPixel += green;
        newPixel = newPixel << 8;
        newPixel += blue;

        return newPixel;

    }




    public static void main(String[] args) {
        System.load("d://disk1/libjpeg-9.dll");
        System.load("d://disk1/libpng-3.dll");
        System.load("d://disk1/NativeImageIOJNI.dll");
        NativeImageIO jniDemo = new NativeImageIO();
//        int png = jniDemo.write(arr, 235, 321, "d:/test/", "test" + System.currentTimeMillis() + ".png", "png");
        int width = 1032;
        int height = 1032;
        byte[] array = FileUtil.readBytes("D:\\disk1\\两相柜-20220901115459701.dat");
        byte[] bytes = BayerUtil.writeBayerBmpFile(array, width, height);

        System.out.println("liangxianggui.bytes.leng=" + bytes.length + ",width=" +  width + ",height=" + height);

        int png = jniDemo.write2BGRAndScale(bytes, height, width, "D:\\disk1\\", "xx两相柜" + System.currentTimeMillis() + ".png", "png", 1);
        System.out.println(png);
    }
}
